/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package stagingetl;

import java.io.FileInputStream;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.io.File;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;

import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;

import parsers.XmlParsing;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import org.apache.commons.beanutils.DynaBean;

import org.apache.commons.beanutils.RowSetDynaClass;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author joen
 */
public class Stagingetl {
    public static final Logger logger = LoggerFactory.getLogger(Stagingetl.class);
    public static Properties properties = new Properties();
    private static DateFormat df = new SimpleDateFormat("yyyy/MM/dd - HH:mm:ss");
    private static Date dNow;
    private static Long now, lstartTime, lstopTime;
    private static String startTime, endTime;
    private static DbPool dbPool = new DbPool();
    private static ArrayList strcMap = new ArrayList();
    private static ArrayList strcType = new ArrayList();
    private static String strString = "";
    private static int itrcounter = 0;
    private static int i = 0;
    private static boolean isHoliday = false;
    private static XmlParsing xmlParse;
    private static String dbTargetType = "";
    private static String strStatement = "";
    private static LinkedList<String> fileList = new LinkedList<String>();
    
    /**
     * @param args the command line arguments
     */
    
    public Stagingetl(String[] args) throws Exception {
        InputStream inputStream = null;
        if (args.length == 0) {
            inputStream = Stagingetl.class.getResourceAsStream("config.properties");
        } else {
            inputStream = new FileInputStream(args[0].trim());
        }
        properties.load(inputStream);
        inputStream.close();
    }
    
    private static Long getCurrentTime() {
        return System.currentTimeMillis();
    }
    
    private static boolean cekTimeStart() {
        boolean isStart = false;
        now = getCurrentTime();
        try {
            lstartTime = df.parse(startTime).getTime();
            if (now - lstartTime < 0) {
                isStart = false;
            } else {
                isStart = true;
            }
        } catch (Exception eX) {
            logger.info(eX.getMessage());
        }
        return isStart;
    }
    
    private static boolean cekTimeEnd() {
        boolean isStop = false;
        now = getCurrentTime();
        try {
            lstopTime = df.parse(endTime).getTime();
            if (now - lstopTime < 0) {
                isStop = false;
            } else {
                isStop = true;
            }
        } catch (Exception eX) {
            logger.info(eX.getMessage());
        }
        return isStop;
    }
    
   private static void regSourcePool() throws Exception {
            File file = new File(properties.getProperty("dbsource"));
            JAXBContext sourceContext = JAXBContext.newInstance(DbConnections.class);
            Unmarshaller sourceUnmarshaller = sourceContext.createUnmarshaller();
            DbConnections sourceDB = (DbConnections) sourceUnmarshaller.unmarshal(file);          
            dbPool.createPool(sourceDB);       
   }
   
   private static void regTargetPool() throws Exception {
            File file = new File(properties.getProperty("dbtarget"));
            JAXBContext targetContext = JAXBContext.newInstance(DbConnections.class);
            Unmarshaller targetUnmarshaller = targetContext.createUnmarshaller();
            DbConnections targetDB = (DbConnections) targetUnmarshaller.unmarshal(file);          
            dbTargetType = targetDB.getdbtype(); 
           dbPool.setProperties(targetDB);
            System.out.println("target register success");
   }
   
   private static boolean cekProjobStatus() throws Exception {
       boolean jobStatus = false;
       SimpleDateFormat dsf = new SimpleDateFormat("dd");
       String today = dsf.format(new Date());
       jobStatus = dbPool.cekProjobDate("proxool.source", "A0001.xml").equalsIgnoreCase(today)?true:false;
       return jobStatus;
   }
    
    public static void main(String[] args) {
        try {
            Stagingetl stagingEtl = new Stagingetl(args);
        } catch (Exception eX) {
            logger.info(eX.getMessage());
        }
        
        dbPool.setMapDir(properties.getProperty("sqlmap"));
        // register source pool
        try {
            regSourcePool();
        } catch (Exception rsex) {
            logger.error(rsex.getCause().toString());
        }
        // register target pool
        try {
            regTargetPool();
        } catch (Exception tsex) {
            logger.error(tsex.getCause().toString());
        }
        // cek holiday
        try {
            if (!dbPool.isHoliday("proxool.source", "A0000.xml")) {
               timers();
            } else {
                logger.info("not business day, process will be terminated");
                System.exit(1);
            }
        } catch (Exception hex) {
            logger.error(hex.getCause().toString());
        }
          
        try {
            DateFormat df = new SimpleDateFormat("yyyy/MM/dd-HH:mm:ss");
            dNow = new Date();
            endTime  = df.format(dNow).substring(0,10) + "-" + properties.getProperty("timestop");
            startTime = df.format(dNow).substring(0,10) + "-" + properties.getProperty("timestart");
        } catch (Exception eX) {
            logger.info(eX.getMessage());
        }
       
    }
    
    private static void runStaging() {       
        try {
            System.out.println("staging mulai");
            xmlParse = new XmlParsing(properties.get("migrationconfig").toString()); 
            int count = xmlParse.getChildCount("staginglist", 0, "item");
            ArrayList<String> paramList = new ArrayList<String>();
            for (int z = 0; z < count; z++) {
                paramList.add(xmlParse.getAttributeValue("item", z, "id")); // 0
                paramList.add(xmlParse.getChildValue("item", z, "mode", 0)); // 1
                paramList.add(xmlParse.getChildValue("item", z, "source", 0)); // 2
                paramList.add(xmlParse.getChildValue("item", z, "sourcepool", 0)); // 3
                paramList.add(xmlParse.getChildValue("item", z, "target", 0)); // 4
                paramList.add(xmlParse.getChildValue("item", z, "targetpool", 0)); // 5
                paramList.add(xmlParse.getChildValue("item", z, "targetschema", 0)); // 6
                                
                getData(paramList.toArray(new String[paramList.size()] ) );
                
                paramList.clear();
            }
        } catch (Exception xex) {
            logger.error (xex.getCause().toString());
        }        
        
        if (fileList.size()!=0) {
            try {
                System.out.println("zzzz");
                  Iterator fListIterator = fileList.iterator();
                  while (fListIterator.hasNext()) {
                      try {
                          dbPool.runImports(fListIterator.next().toString());
                      } catch (Exception iex) {
                          logger.error (iex.getCause().toString());
                      }
                  }
//                            dbPool.runImports("aaaa");
            } catch (Exception ex) {
                logger.error(ex.getCause().toString());
            }
        } else {
            System.out.println("zaaa");
        }
        
        System.out.println("Staging Selesai");
        System.exit(1);
    }
        
    private static void getData(String[] params) {
        RowSetDynaClass rscd = null;
        LinkedList<String> colLists = new LinkedList<String>();
        LinkedList<String> typeLists = new LinkedList<String>();
        LinkedList<String> valLists = new LinkedList<String>();
        LinkedList<String> stmtList = new LinkedList<String>();
        // LinkedList<String> fileList = new LinkedList<String>();
        StringBuffer queryBuffer = new StringBuffer();
        StringBuffer tmpBuffer = new StringBuffer();
        String processedFile = "";
        
            try {
                rscd = dbPool.runQueryReturnRecordSet(params[3].toString(), params[2].toString());
                strcMap = dbPool.getStructure(params[3].toString(), params[2].toString());
                strcType = dbPool.getTypeStructure(params[3].toString(), params[2].toString());
            } catch (Exception aex) {
                logger.error(aex.getCause().toString());
            }
            
            
            System.out.println(params[0].toString() + " : start " + df.format(System.currentTimeMillis()));
                int i = strcMap.toArray().length;
                Iterator<DynaBean> dsIterator = rscd.getRows().iterator();
                while (dsIterator.hasNext()) {
                    colLists.clear();
                    typeLists.clear();
                    valLists.clear();
                    DynaBean bean = (DynaBean) dsIterator.next();
                    for (int ii=0; ii < i -1; ii++ )  {
                        try {
                            if (!bean.get(strcMap.get(ii).toString().toLowerCase()).toString().isEmpty()) {
                                colLists.add(strcMap.get(ii).toString().toLowerCase());
                                typeLists.add(strcType.get(ii).toString());
                                if (!dbTargetType.equalsIgnoreCase("mssql")) {
                                    valLists.add(bean.get(strcMap.get(ii).toString().toLowerCase()).toString().replaceAll("'", "\\\\' "));
                                } else {
                                    valLists.add(bean.get(strcMap.get(ii).toString().toLowerCase()).toString().replaceAll("'", "''"));
                                }
                            }
                        } catch (NullPointerException npex) {   }
                    }
                    stmtList.add(dbPool.runSync(colLists, typeLists, valLists, params[5].toString(), params[1].toString(), params[4].toString()) + "\r\n");
                 } // end while
                
                int rGroup = stmtList.size()%Integer.parseInt(properties.getProperty("rowiterator"));
                int fGroup = (int) (Math.floor(stmtList.size()/Integer.parseInt(properties.getProperty("rowiterator"))) + (rGroup!=0?1:0));
                
                if (fGroup!=0) {
                    String fileName = properties.getProperty("exportdir") + params[4].toString().trim();
                    Iterator stmtIterator = stmtList.iterator();
                    int rCount = 0;
                    int iCount = 0;
                    while (stmtIterator.hasNext()) {
                        if (rCount==0) {
                            tmpBuffer.append("use " + params[6].toString().trim() + ";\r\n");
                            if (properties.getProperty("targetdb").toString().equalsIgnoreCase("mssql")) {
                                // tmpBuffer.append("go\r\n");
                            }
                            if (iCount == 0 ) {
                                    if (params[1].toString().equalsIgnoreCase("truncate")) {
                                            tmpBuffer.append("truncate table " + params[4].toString().trim() + ";\r\n");
                                        if (properties.getProperty("targetdb").toString().equalsIgnoreCase("mssql")) {
                                     //       tmpBuffer.append("go\r\n");
                                        }
                                    }
                            }
                        }
                        
                        tmpBuffer.append(stmtIterator.next());
                        rCount += 1;                       
                        
                        if (iCount == fGroup - 1) {
                            if (rCount == rGroup) {
                                fileList.add(properties.getProperty("exportdir") + params[4].toString().trim() + (iCount==0?"":iCount) + ".sql");
                                writeToFile(properties.getProperty("exportdir") + params[4].toString().trim() + (iCount==0?"":iCount) + ".sql", tmpBuffer);
                                tmpBuffer.delete(0, tmpBuffer.length());
                            }
                        } else {
                            if (rCount == Integer.parseInt(properties.getProperty("rowiterator"))) {
                                fileList.add(properties.getProperty("exportdir") + params[4].toString().trim() + (iCount==0?"":iCount) + ".sql");
                                writeToFile(properties.getProperty("exportdir") + params[4].toString().trim() + (iCount==0?"":iCount) + ".sql", tmpBuffer);
                                tmpBuffer.delete(0, tmpBuffer.length());
                                iCount += 1;
                                rCount = 0;
                            }
                        }
                        
                    }
                }
                
                
/*                System.out.println("-- start importing to target db");
                Iterator fileIterator = fileList.iterator();
                Process process = null;
                while (fileIterator.hasNext()) {
                    processedFile = fileIterator.next().toString();
                    try {
                        System.out.println("  importing " + processedFile.toString());
                        process = Runtime.getRuntime().exec(properties.getProperty("importcmd").trim() + " " + processedFile.trim());
                        int exitVal = process.waitFor();
                        if (exitVal==0) {
                            System.out.println("   done reading");
                        }
                    } catch (Exception pex) {
                        logger.error ("error on processing import datafile : " + pex.getCause().toString());
                    } finally {
                        if (process!=null) {
                            process.destroy();
                        }
                    }
                }
            System.out.println("-- done importing to target db"); */
            System.out.println(params[0].toString() + " : done " +  df.format(System.currentTimeMillis()));
    }
    
    private static void writeToFile(String fileName, StringBuffer fileContet) {
        // System.out.println("Start Writing to file");
        File file = new File(fileName);
        if (file.exists()) {
            file.delete();
        }
        try {
            file.createNewFile();
            FileWriter fWriter = new FileWriter(file.getAbsoluteFile());
            BufferedWriter bWriter = new BufferedWriter(fWriter);
            bWriter.write(fileContet.toString());
            bWriter.close();
            fWriter.close();
        } catch (IOException ioex) {
            logger.error(ioex.getCause().toString());
        }
    }
    
    private static void timers() throws Exception {
        System.out.println("Start Projob end status cek");
        Timer timer = new Timer("migrate timer");
        ProcessCek pcek = new ProcessCek();
        timer.schedule(pcek, 0, 1000L * Integer.parseInt(properties.getProperty("refreshperiod")));
    }
    
    private static class ProcessCek extends TimerTask {

        @Override
        public void run() {
            try {
                if (cekProjobStatus()) {
                    System.out.println("Projobs Done - proceeding to staging process");
                    runStaging();
                } else {
                    System.out.println("Projobs Not Done yet -- waiting ");
                }
            } catch (Exception ex) {
                logger.error(ex.getCause().toString());
                System.exit(1);
            }
        }
        
    }
    
}  // end class
